﻿// <copyright file="MemShapeProvider.cs" company="Signal Processing Lab, Wuhan University">
// Copyright (c) 2009-2010 All Right Reserved
// </copyright>
// <author>Xinping Deng</author>
// <email>dentoby@gmail.com</email>
// <date>2010-4</date>
// <summary>This is part of Image.NET project.</summary>

namespace SPLWHU.Core.Vectors
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    /// <summary>
    /// Stores the features in the memory. This can improve the performance.
    /// </summary>
    /// <typeparam name="T">The geometry type.</typeparam>
    public class MemShapeProvider<T> : IShapeProvider where T : Geometry, new()
    {
        /// <summary>
        /// The max count of features to store in this provider.
        /// </summary>
        private static readonly int MaxCount = 100;

        /// <summary>
        /// The features in memory.
        /// </summary>
        private List<Feature> features;

        /// <summary>
        /// The feature collection.
        /// </summary>
        private FeatureCollection featureCollection;

        /// <summary>
        /// Initializes a new instance of the <see cref="MemShapeProvider&lt;T&gt;"/> class.
        /// </summary>
        /// <param name="featureCollection">The feature collection <see cref="FeatureCollection"/>.</param>
        public MemShapeProvider(FeatureCollection featureCollection)
        {
            this.featureCollection = featureCollection;
            this.features = new List<Feature>();
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="MemShapeProvider&lt;T&gt;"/> class.
        /// </summary>
        /// <param name="featureCollection">The feature collection.</param>
        /// <param name="features">The features.</param>
        public MemShapeProvider(FeatureCollection featureCollection, List<Feature> features)
        {
            this.featureCollection = featureCollection;
            this.features = features;
        }

        /// <summary>
        /// Adds a feature by specifying the geometry.
        /// </summary>
        /// <param name="geometry">The geometry.</param>
        public void Add(T geometry)
        {
            this.features.Add(new Feature(geometry));
        }

        /// <summary>
        /// Gets the geometry at the specified index.
        /// </summary>
        /// <param name="index">The index.</param>
        /// <returns>The geometry at the specified position.</returns>
        public T GetGeometry(int index)
        {
            return (T)this.features[index].Geometry;
        }

        #region IShapeProvider Members

        /// <summary>
        /// Gets the count of geometries in the collection.
        /// </summary>
        /// <value>The number of geometries.</value>
        public int Count
        {
            get { return this.features.Count; }
        }

        /// <summary>
        /// Gets or sets the feature at the specified index.
        /// </summary>
        /// <value></value>
        /// <returns>The geometry at the specified index.</returns>
        public Feature this[int index]
        {
            get
            {
                return this.features[index];
            }

            set
            {
                this.features[index] = value;
            }
        }

        /// <summary>
        /// Adds a new feature to the collection.
        /// </summary>
        /// <param name="feature">The feature added.</param>
        public void Add(Feature feature)
        {
            this.features.Add(feature);

            this.ChangeProvider();
        }

        /// <summary>
        /// Adds an array of features to the collection.
        /// </summary>
        /// <param name="features">The features added.</param>
        public void Add(Feature[] features)
        {
            foreach (Feature f in features)
            {
                this.features.Add(f);
            }

            this.ChangeProvider();
        }

        /// <summary>
        /// Adds a list of features to the collection.
        /// </summary>
        /// <param name="features">The features added.</param>
        public void Add(List<Feature> features)
        {
            foreach (Feature f in features)
            {
                this.features.Add(f);
            }

            this.ChangeProvider();
        }

        /// <summary>
        /// Removes the geometry at the specifed index.
        /// </summary>
        /// <param name="index">The index.</param>
        public void RemoveAt(int index)
        {
            this.features.RemoveAt(index);
        }

        /// <summary>
        /// Removes the specified feature.
        /// </summary>
        /// <param name="feature">The feature removed.</param>
        public void Remove(Feature feature)
        {
            this.features.Remove(feature);
        }

        /// <summary>
        /// Clears all features in this provider.
        /// </summary>
        public void Clear()
        {
            this.features.Clear();
        }

        /// <summary>
        /// Gets the geometries within the bounding box.
        /// </summary>
        /// <param name="bbox">The bounding box.</param>
        /// <returns>A list of geometries.</returns>
        public List<Feature> GetFeatures(BoundingBox bbox)
        {
            List<Feature> ret = new List<Feature>();

            foreach (Feature f in this.features)
            {
                if (f.Geometry.GetExtents().Intersects(bbox))
                {
                    ret.Add(f);
                }
            }

            return ret;
        }

        /// <summary>
        /// Gets the enumerator of all features.
        /// </summary>
        /// <returns>The enumerator to access the features.</returns>
        public IEnumerable<Feature> GetFeatures()
        {
            return this.features;
        }

        #endregion

        /// <summary>
        /// Changes the provider of <see cref="FeatureCollection"/> if the count is large.
        /// </summary>
        private void ChangeProvider()
        {
            if (this.features.Count >= MemShapeProvider<T>.MaxCount)
            {
                this.featureCollection.Provider = new OgrShapeProvider<T>();
                this.featureCollection.Add(this.features);
            }
        }
    }
}
